"use client"; import { useState, useEffect, useCallback } from "react"; import { useRouter } from "next/navigation"; import Link from "next/link"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Progress } from "@/components/ui/progress"; import { Badge } from "@/components/ui/badge"; import { Edit, ArrowLeft, Loader2, RefreshCw } from "lucide-react"; import { useToast } from "@/components/ui/use-toast"; import { formatCurrency } from "@/lib/utils"; import { api } from "@/lib/api"; import { GoalProgress } from "../components/goals-list"; import { use } from "react"; export default function GoalDetailPage({ params }: { params: { id: string } }) { // Unwrap params Promise using React.use() const unwrappedParams = use(params); const id = unwrappedParams.id; const goalId = parseInt(id); const [goal, setGoal] = useState(null); const [loading, setLoading] = useState(true); const [refreshing, setRefreshing] = useState(false); const router = useRouter(); const { toast } = useToast(); const fetchGoalDetails = useCallback(async () => { try { console.log(`Fetching goal details for ID: ${goalId}`); setLoading(true); // Add cache-busting parameter const response = await api.get(`/goals/${goalId}/progress?cache=${new Date().getTime()}`); console.log("Goal details received:", response.data); // Validate and normalize data const data = response.data; if (data && data.goal) { const sanitizedData = { ...data, goal: { ...data.goal, targetAmount: Number(data.goal.targetAmount) || 0, currentAmount: Number(data.goal.currentAmount) || 0, createdAt: data.goal.createdAt || new Date().toISOString(), }, percentComplete: Number(data.percentComplete) || 0, amountRemaining: Number(data.amountRemaining) || 0, daysRemaining: Number(data.daysRemaining) || 0, requiredPerDay: Number(data.requiredPerDay) || 0, requiredPerMonth: Number(data.requiredPerMonth) || 0, }; console.log("Processed goal data:", sanitizedData); setGoal(sanitizedData); } else { console.error("Invalid goal data format:", data); throw new Error("Invalid goal data received"); } } catch (error) { console.error("Error fetching goal details:", error); toast({ title: "Error", description: "Failed to fetch goal details. Please try again.", variant: "destructive", }); router.push("/goals"); } finally { setLoading(false); } }, [goalId, toast, router]); // Fetch goal details when component mounts useEffect(() => { if (!id) { toast({ title: "Error", description: "Goal ID is missing. Please try again.", variant: "destructive", }); router.push("/goals"); return; } fetchGoalDetails(); }, [id, fetchGoalDetails, router, toast]); const recalculateProgress = async () => { if (isNaN(goalId)) { toast({ title: "Error", description: "Invalid goal ID", variant: "destructive", }); return; } try { setRefreshing(true); await api.post(`/goals/${goalId}/recalculate`); toast({ title: "Progress recalculated", description: "Your goal progress has been recalculated based on transactions.", }); fetchGoalDetails(); } catch (error) { toast({ title: "Error", description: "Failed to recalculate goal progress. Please try again.", variant: "destructive", }); console.error("Error recalculating goal progress:", error); } finally { setRefreshing(false); } }; if (loading) { return (
); } if (!goal) { return (

Goal not found or access denied.

); } const { goal: goalData, percentComplete, amountRemaining, daysRemaining, requiredPerDay, requiredPerMonth, onTrack } = goal; const isCompleted = goalData.status === "Achieved"; return (

{goalData.name}

{isCompleted ? "Goal has been achieved 🎉" : onTrack ? "Progress is on track" : "Progress is behind schedule"}

Goal Progress {isCompleted ? "Achieved" : onTrack ? "On Track" : "Behind"}
Completion {Math.round(percentComplete)}%

Target Amount

{formatCurrency(goalData.targetAmount)}

Current Amount

{formatCurrency(goalData.currentAmount)}

Remaining

{formatCurrency(amountRemaining)}

{goalData.targetDate && (

Target Date

{new Date(goalData.targetDate).toLocaleDateString()}

)} {daysRemaining > 0 && ( <>

Days Remaining

{daysRemaining} days

Required Per Day

{formatCurrency(requiredPerDay)}

Required Per Month

{formatCurrency(requiredPerMonth)}

)}
Goal Details

Goal Name

{goalData.name}

Purpose

{goalData.name}

Status

{goalData.status}

Created

{new Date(goalData.createdAt).toLocaleDateString()}

{isCompleted ? (

🎉 Goal achieved!

Congratulations on achieving your financial goal.

) : (
)}
); }